#include <jni.h>
#include <string>
#include <vector>
#include <cstring>
#include <unistd.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <arpa/inet.h>
#include <android/log.h>
#include <unordered_map>
#include "../../base/string_utils.h"
#include "../../base/logger.h"
#include "../network.hpp"

#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "network_utils", __VA_ARGS__))

namespace license {
    namespace os {
        using namespace std;

        FUNCTION_RETURN getAdapterInfos(vector<OsAdapterInfo> &adapterInfos) {
            std::unordered_map<string, OsAdapterInfo> adapterByName;

            FUNCTION_RETURN f_return = FUNC_RET_OK;
            int sd, ifc_num, i;
            struct ifconf ifc;
            struct ifreq ifr[50];
            char buf[1024];

            sd = socket(AF_INET, SOCK_DGRAM, 0);
            if (sd < 0) {
                LOG_WARN("socket creation failed");
                return FUNC_RET_ERROR;
            }

            ifc.ifc_len = sizeof(buf);
            ifc.ifc_buf = buf;
            if (ioctl(sd, SIOCGIFCONF, &ifc) < 0) {
                close(sd);
                LOG_WARN("ioctl SIOCGIFCONF failed");
                return FUNC_RET_ERROR;
            }

            ifc_num = ifc.ifc_len / sizeof(struct ifreq);

            for (i = 0; i < ifc_num; ++i) {
                struct ifreq *item = &ifr[i];
                strcpy(item->ifr_name, ifc.ifc_req[i].ifr_name);
                if (ioctl(sd, SIOCGIFADDR, item) < 0) {
                    continue;
                }

                string if_name(item->ifr_name);
                OsAdapterInfo *currentAdapter;
                if (adapterByName.find(if_name) == adapterByName.end()) {
                    OsAdapterInfo newAdapter;
                    memset(&newAdapter, 0, sizeof(OsAdapterInfo));
                    strncpy(newAdapter.description, item->ifr_name, LCC_ADAPTER_DESCRIPTION_LEN);
                    adapterByName[if_name] = newAdapter;
                }

                auto it = adapterByName.find(if_name);
                currentAdapter = &it->second;

                struct sockaddr_in *addr = (struct sockaddr_in *)&item->ifr_addr;
                uint32_t iaddr = addr->sin_addr.s_addr;
                currentAdapter->ipv4_address[0] = (iaddr & 0x000000ff);
                currentAdapter->ipv4_address[1] = (iaddr & 0x0000ff00) >> 8;
                currentAdapter->ipv4_address[2] = (iaddr & 0x00ff0000) >> 16;
                currentAdapter->ipv4_address[3] = (iaddr & 0xff000000) >> 24;

                if (ioctl(sd, SIOCGIFHWADDR, item) == 0) {
                    for (int j = 0; j < 6; ++j) {
                        currentAdapter->mac_address[j] = (unsigned char)item->ifr_hwaddr.sa_data[j];
                    }
                }
            }

            close(sd);

            if (adapterByName.size() == 0) {
                f_return = FUNC_RET_NOT_AVAIL;
            } else {
                f_return = FUNC_RET_OK;
                adapterInfos.reserve(adapterByName.size());
                for (auto &it : adapterByName) {
                    adapterInfos.push_back(it.second);
                }
            }
            return f_return;
        }

    }  // namespace os
}  // namespace license
